function objectToString(o: any) {
  return Object.prototype.toString.call(o);
}

// 是否为 空
export function isEmpty(arg: any): boolean {
  if (arg === undefined || arg === null || arg === "") return true;
  if (typeof arg === "number" && isNaN(arg)) return true;
  return false;
}

// 是否不为 空
export function isNotEmpty(arg: any): boolean {
  return !isEmpty(arg);
}

// 是否为 Object
export function isObject(arg: any): boolean {
  return objectToString(arg) === "[object Object]";
}

// 是否为 Array
export function isArray(arg: any): boolean {
  if (Array.isArray) {
    return Array.isArray(arg);
  }
  return objectToString(arg) === "[object Array]";
}

// 是否为 RegExp
export function isRegExp(regex: any): boolean {
  return objectToString(regex) === "[object RegExp]";
}

// 是否为 Function
export function isFunction(arg: any): boolean {
  return typeof arg === "function";
}

// 是否为 Boolean
export function isBoolean(arg: any): boolean {
  return typeof arg === "boolean";
}

// 是否为 number
export function isNumber(arg: any): boolean {
  return typeof arg === "number" && !isNaN(arg);
}

// 是否为 int
export function isInt(arg: any): boolean {
  return typeof arg === "number" && arg % 1 === 0;
}

// 是否为 string
export function isString(arg: any): boolean {
  return typeof arg === "string";
}

// 是否为 numberString
export function isNumberString(arg: any): boolean {
  return typeof arg === "string" && arg !== "" && !isNaN(Number(arg));
}

// 是否为 null/undefined
export function isNullOrUndefined(arg: any): boolean {
  return arg == null; // 非严格比较
}

// 是否为 undefined
export function isUndefined(arg: any): boolean {
  return typeof arg === "undefined";
}

// 是否为 null
export function isNull(arg: any): boolean {
  return arg === null; // 严格比较
}

// 是否为 日期(YYYY-MM-DD)
export function isDate(arg: string): boolean {
  const regex = new RegExp(
    `^\\d{2}-(?:1[0-2]|0[1-9])-(?:3[0-1]|[1-2][0-9]|0[1-9])$`,
    "g"
  );
  return regex.test(arg);
}

// 是否为 日期时间(YYYY-MM-DD HH:mm:ss)
export function isDateTime(arg: string): boolean {
  const regex = new RegExp(
    `^\\d{4}-(?:1[0-2]|0[1-9])-(?:3[0-1]|[1-2][0-9]|0[1-9])\\s(?:2[0-3]|1[0-9]|0[0-9]):(?:[1-5][0-9]|0[0-9]):(?:[1-5][0-9]|0[0-9])$`,
    "g"
  );
  return regex.test(arg);
}

// 是否为json字符串
export function isJsonString(arg: string): boolean {
  try {
    JSON.parse(arg);
    return true;
  } catch (e) {
    return false;
  }
}

// 是否含中文
export function isChinese(arg: any): boolean {
  const regex = new RegExp("[\u4e00-\u9fa5]");
  return regex.test(arg);
}

// 是否为手机号
export function isMobile(arg: string): boolean {
  return /^1\d{10}$/.test(arg);
}

// 是否为邮箱
export function isEmail(arg: any): boolean {
  const regex = new RegExp("^([a-zA-z0-9]+[-_.]?)+@[a-zA-Z0-9]+.[a-z]+$");
  return regex.test(arg);
}

// 是否为银行卡号
export function isBank(arg: any): boolean {
  const regex = new RegExp("^[1-9]\\d{9,29}$");
  return regex.test(arg);
}

// 是否为版本号
export function isVersion(arg: any): boolean {
  return /^\d+(?:\.\d+){2}$/.test(arg);
}

// 数字/字母/下划线/减号
export function isAccount(arg: any, min = 5, max = 16): boolean {
  const regex = new RegExp(`^[a-zA-Z0-9_-]{${min},${max}}$`);
  return regex.test(arg);
}

// 包含字母、数字、特殊符，任意2种
export function isPwd(arg: any, min = 8, max = 16): boolean {
  const regex = new RegExp(
    `(?!^[0-9]+$)(?!^[A-z]+$)(?!^[^A-z0-9]+$)^[^\\s\u4e00-\u9fa5]{${min},${max}}$`
  );
  return regex.test(arg);
}

// 是否相等, 支持对象和数组类型
export function isEqual(a: any, b: any): boolean {
  if (isEmpty(a) || isEmpty(b)) return a === b;
  if (typeof a != typeof b) return false;
  if (isObject(a)) {
    if (Object.keys(a).length != Object.keys(b).length) return false;
    for (const key in a) {
      if (!Object.keys(b).includes(key) || !isEqual(a[key], b[key])) {
        return false;
      }
      return true;
    }
  }
  if (isArray(a)) {
    if (a.length != b.length) return false;
    for (var i = 0; i < a.length; i++) {
      if (!isEqual(a[i], b[i])) return false;
    }
    return true;
  }
  return a === b;
}
